package com.tgra;

import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;

import com.badlogic.gdx.Gdx;

public class Maze {

	public static final int MAZE_X = 4;
	public static final int MAZE_Z = 4;
	public static final float LENGTH = Cell.WALL_LENGTH;
	public static final float THICKNESS = Cell.WALL_THICKNESS;

	Cell[][] cells;
	Stack<Cell> cellStack;
	ArrayList<Cell> neighbours;
	Cell goalCell;
	
	//Smiður til þess að frumstilla maze
	public Maze() {
		
		cells = new Cell[MAZE_X + 1][MAZE_Z + 1];
		cellStack = new Stack<Cell>();

		for (int x = 0; x <= MAZE_X; x++) {
			for (int z = 0; z <= MAZE_Z; z++) {
				cells[x][z] = new Cell(false, false, true);
				cells[x][z].x = x;
				cells[x][z].z = z;
				cells[x][z].westWall = true;
				cells[x][z].northWall = true;
				if (x == MAZE_X && z != MAZE_Z) {
					cells[x][z].floor = false;
				}
				if (z == MAZE_Z && x != MAZE_X) {
					cells[x][z].floor = false;
				}
				if (z == MAZE_Z && x == MAZE_X) {
					cells[x][z].floor = false;
				}					
			}
		}
		// Fall sem býr til random maze útrfá upphafs cellu.
		generateRandomMaze(cells[0][0]);
	}
	// Fall sem ber saman currentCell og nextCell og tekur niður vegginn á milli þeirra.
	public void removeWall(int currCellX, int currCellZ, int nextCellX, int nextCellZ){
		if (currCellX < nextCellX){
			cells[nextCellX][nextCellZ].westWall = false;
		}
		if (currCellX > nextCellX){
			cells[currCellX][currCellZ].westWall = false;
		}
		if (currCellZ < nextCellZ){
			cells[nextCellX][nextCellZ].northWall = false;
		}
		if (currCellZ > nextCellZ){
			cells[currCellX][currCellZ].northWall = false;
		}
	}
	// Fall sem finnur og skilar ArrayLista með öllum nágrönnum currentCell. 
	public ArrayList<Cell> checkNeighbours(int x, int z) {
		ArrayList<Cell> neighbours = new ArrayList<Cell>();
		
		if ( x > 0) {
			if (!cells[x-1][z].isVisted){
				neighbours.add(cells[x-1][z]);
			}
		}
		if ( z > 0) {
			if (!cells[x][z-1].isVisted){
				neighbours.add(cells[x][z-1]);
			}
		}
		if ( x < MAZE_X-1) {
			if (!cells[x+1][z].isVisted){				
				neighbours.add(cells[x+1][z]);
			}
		}
		if ( z < MAZE_Z-1) {
			if (!cells[x][z+1].isVisted){				
				neighbours.add(cells[x][z+1]);
			}
		}		
		return neighbours;
	}
	// Fall sem notar stack (LIFO) til þess að halda utan um cellur sem eiga nágranna. Fallið athugar hvort
	// current cella á nágranna og ef svo er þá er ein af nágrönnunum valin af handahófi, pushað á stackinn
	// og sett sem currentCelll. Ef allir nágrannar í cellunni hefur verið skoðaðir þá eru cellunni
	// popað úr stacknum og sú cella valin sem næsta CurrentCell. Þetta keyrir þangað til að allar cellur í
	// tvívíða hafa verið skoðaðar. Þegar fallið hefur skoðað allar cellurnar er síðasta cellan sem var á
	// stacknum sett sem goalCell. 
	// Stuðst var við sauðakóða af síðunni: http://www.mazeworks.com/mazegen/mazetut/index.htm
	public void generateRandomMaze(Cell currentCell){
		int totalCells = MAZE_X * MAZE_Z;
		int visitCells = 1;
		currentCell.isVisted = true;
		while (visitCells < totalCells) {
			neighbours = checkNeighbours(currentCell.x, currentCell.z);
			if (!neighbours.isEmpty()){
					Random randomNeighbourCell = new Random();
					Cell chosenCell = neighbours.get(randomNeighbourCell.nextInt(neighbours.size()));
					chosenCell.isVisted = true;
					removeWall(currentCell.x, currentCell.z, chosenCell.x , chosenCell.z);
					cellStack.push(chosenCell);
					currentCell = chosenCell;
					visitCells += 1;		
			}
			else {
				if (!cellStack.empty()){					
					currentCell = cellStack.pop();
				}
			}				
		}
		currentCell.isGoal = true;
		goalCell = currentCell;
	}

	boolean hasNorthWall(int x, int z) {
		return cells[x][z].northWall;
	}

	boolean hasWestWall(int x, int z) {
		return cells[x][z].westWall;
	}

	boolean hasSouthWall(int x, int z) {
		if (z == MAZE_Z)
			return true;
		return cells[x][z+1].northWall;
	}

	boolean hasEastWall(int x, int z) {
		if (x == MAZE_X)
			return true;
		return cells[x+1][z].westWall;
	}
	
	Cell getGoalCell(){
		return goalCell;
	}

	public void draw() {
		for (int x = 0; x <= MAZE_X; x++) {
			for (int z = 0; z <= MAZE_Z; z++) {
				Gdx.gl11.glPushMatrix();
				Gdx.gl11.glTranslatef((float)x, 0.0f, (float)z);
				cells[x][z].draw();
				Gdx.gl11.glPopMatrix();
			}
		}
	}
}
